const { redis, isImgExists, Mailer, random, getLike } = require('../common')
const { Article, User, Category, Comment, Like } = require('../models')
const { Existing, AuthFailed, NotFound } = require('../core/http-exception')
const { ADMIN, SP_ADMIN } = require('../middleware/auth')
const { Op } = require('sequelize')
const xss = require('xss')
const path = require('path')

class ArticleController {
  static async create(data, auth) {
    const category = await Category.findOne({
      where: {
        id: data.get('category_id')
      }
    })

    if(!category){
      throw new NotFound('没有找到这个分类');
    }

    if (data.get('label')) {
      let labels = data.get('label').split(',')
      for (let i = 0; i < labels.length; i++) {
        let item = labels[i]
        const key = `category_name_${item}_type_label`
        let flag = await redis.get('content', key)
        if (flag) continue
        let v = await Category.findOne({
          where: {
            name: item
          }
        })
        if (!v) {
          throw new NotFound('无效的标签')
        }
        await redis.set('content', key, true, 60 * 60 * 24 * 3)
      }
    }

    data.get('cover') && await isImgExists(data.get('cover'));

    return await Article.create({
      title: xss(data.get('title')),
      content: xss(data.get('content')),
      html: data.get('html'),
      user_id: auth.id,
      category_id: category.id,
      cover: data.get('cover'),
      status: data.get('status'),
      label: data.get('label')
    })
  }

  static async getArticle(data, data2, auth) {
    const key = `article_content_${data.get('id')}_edit_${data2.get('edit')}`;
    const cache = await redis.get('content', key)
    if (cache) {
      const result = JSON.parse(cache)
      result.cache = true;
      result.likes = await getLike('article', result.id, auth && auth.id)
      return result;
    }

    let article = await Article.findOne({
      where: {
        id: data.get('id'),
        status: 1
      },
      attributes: {
        exclude: ['deleted_at', 'user_id']
      },
      include: [{
        model: User,
        as: 'user',
        attributes: ['username', 'portrait', 'uid', 'information']
      }, {
        model: Category,
        as: 'category',
        attributes: ['name'],
      }]
    })

    if (!article) {
      throw new NotFound('不存在这篇文章')
    }

    if (data2.get('edit')) {
      if (!auth || (auth.uid != article.user.uid && auth.scope < ADMIN)) {
        throw new AuthFailed('你没有权限获取markdown格式文章')
      }
      delete article.dataValues.html;
    } else {
      article = await article.update({
        browse: article.browse + 1
      })
      delete article.dataValues.content;
    }

    await redis.set(
      'content',
      key,
      JSON.stringify(article),
      60
    )
    
    article.dataValues.likes = await getLike('article', article.id, auth && auth.id)

    return article
  }

  static async delete(data, auth){
    let article = await Article.findOne({
      where: {
        id: data.get('id')
      },
      attributes: {
        exclude: ['deleted_at']
      },
      include: [
        {
          model: User,
          as: 'user',
          attributes: ['scope']
        }
      ]
    })
    if(!article){
      throw new NotFound('不存在这篇文章')
    }
    if (
      article.user_id != auth.id &&
      parseInt(auth.scope) < parseInt(article.user.scope)
    ) {
      throw new AuthFailed('你没有权限删除这篇文章')
    }

    await article.destroy();
  }

  static async update(data, auth){
    let article = await Article.findOne({
      where: {
        id: data.get('id')
      },
      attributes: {
        exclude: ['deleted_at']
      },
      include: [
        {
          model: User,
          as: 'user',
          attributes: ['scope']
        }
      ]
    })
    if (!article) {
      throw new NotFound('不存在这篇文章')
    }

    if (
      article.user_id != auth.id &&
      parseInt(auth.scope) < parseInt(article.user.scope)
    ) {
      throw new AuthFailed('你没有权限修改这篇文章')
    }

    if(data.get('category_id')){
      const category = await Category.findOne({
        where: {
          id: data.get('category_id')
        }
      })

      if (!category) {
        throw new NotFound('没有找到这个标签')
      }
    }

    data.get('cover') && await isImgExists(data.get('cover'))

    if (data.get('label')) {
      let labels = data.get('label').split(',')
      for (let i = 0; i < labels.length; i++) {
        let item = labels[i]
        const key = `category_name_${item}_type_label`
        let flag = await redis.get('content', key)
        if (flag) continue
        let v = await Category.findOne({
          where: {
            name: item
          }
        })
        if (!v) {
          throw new NotFound('无效的标签')
        }
        await redis.set('content', key, true, 60 * 60 * 24 * 3)
      }
    }

    await article.update({
      title: data.get('title', article.title),
      content: data.get('content', article.content),
      html: data.get('html', article.html),
      category_id: data.get('category_id', article.category_id),
      cover: data.get('cover', article.cover),
      label: data.get('label', article.label)
    })

    const key = `article_content_${data.get('id')}`
    await redis.del('content', key);
  }

  static async list(data, flag = false, auth){
    let { page = 1, size = 10, keyword, user_id, order = 'DESC', label, status, getCache = true } = data.get();
    const key = `article_list_page_${page}_size_${size}_keyword_${keyword}_user_id_${user_id}_order_${order}_flag_${flag}_label_${label}_status_${status}`;
    const cache = await redis.get('content', key);
    if(cache && getCache != 'false'){
      let res = JSON.parse(cache);
      res.cache = true;
      for (let i = 0; i < res.list.length; i++) {
        let item = res.list[i]
        item.likes = await getLike('article', item.id, auth && auth.id)
      }
      return res;
    }
    let filter = {
      status: flag ? 2 : 1
    }

    if(user_id){
      const user = await User.findOne({
        where: {
          uid: user_id
        }
      })
      if(user){
        filter.user_id = user.id;
      }
    }

    if(status && auth){
      filter.user_id = auth.id;
      filter.status = status;
    }

    if (keyword) {
      filter.title = {
        [Op.like]: `%${xss(keyword)}%`
      }
    }

    if (label) {
      filter.label = {
        [Op.like]: `%${xss(label)}%`
      }
    }

    const articles = await Article.findAndCountAll({
      limit: parseInt(size),
      offset: (page - 1) * parseInt(size),
      where: filter,
      order: [['created_at', order]],
      attributes: {
        exclude: ['deleted_at', 'content', 'html', 'user_id', 'browse', 'category_id']
      },
      include: [{
        model: Category,
        as: 'category',
        attributes: ['name']
      }, {
        model: User,
        as: 'user',
        attributes: ['username', 'uid']
      }],
    })
    
    const result = {
      list: articles.rows,
      meta: {
        total: articles.count,
        page_size: size,
        current_page: parseInt(page),
        total_pages: Math.ceil(articles.count / size)
      }
    }

    if(getCache != 'false'){
      await redis.set('content', key, JSON.stringify(result), 60)
    }

    for (let i = 0; i < result.list.length; i++) {
      let item = result.list[i]
      item.dataValues.likes = await getLike('article', item.id, auth && auth.id)

    }

    return result;
  }

  static async disable(data, ctx){
    const article = await Article.findOne({
      where: {
        id: data.get('id')
      },
      include: [{
        model: User,
        as: 'user',
        attributes: ['email', 'username', 'scope']
      }]
    })

    if(!article){
      throw new NotFound('没有找到这篇文章')
    }

    if(ctx.auth.scope < article.user.scope){
      throw new AuthFailed('你没有权限禁用这篇文章');
    }

    const admin = await User.findOne({
      where: {
        id: ctx.auth.id
      }
    })

    if(article.status != 1){
      throw new AuthFailed('这篇文章不是可以禁用的状态(已经禁用或这是一篇草稿)');
    }

    await article.update({
      status: 2
    })

    const flag = await Mailer.send({
      to: article.user.email,
      type: 'disable_article',
      title: `${article.user.username}您好！您的《${article.title}》被禁用！`,
      article_title: article.title,
      admin_name: admin.username,
      info: data.get('info'),
      ctx
    })

    return flag;
  }

  static async requestUnlock(data, ctx){
    const article = await Article.findOne({
      where: {
        id: data.get('id')
      },
      include: [{
        model: User,
        as: 'user',
        attributes: ['username', 'email']
      }]
    })

    if (!article) {
      throw new NotFound('没有找到这篇文章')
    }

    if(article.user_id != ctx.auth.id){
      throw new AuthFailed('你没有权限')
    }

    if(article.status != 2){
      throw new AuthFailed('文章不是禁用状态');
    }

    // 随便找一个管理员，让他处理
    const users = await User.findAndCountAll({
      where: {
        scope: {
          [Op.or]: [SP_ADMIN, ADMIN]
        }
      },
      attributes: ['email', 'username']
    })

    const admin = users.rows[random(users.count)]

    await Mailer.delay(`request_unlock_article_email_${article.user.email}`, 60 * 60 * 24)
    
    const flag = await Mailer.send({
      to: admin.email,
      type: 'request_unlock_article',
      title: `《${article.title}》的解禁请求！`,
      article_title: article.title,
      article_user_username: article.user.username,
      ctx
    })

    return flag;
  }

  static async unlock(data){
    const article = await Article.findOne({
      where: {
        id: data.get('id')
      },
      include: [
        {
          model: User,
          as: 'user',
          attributes: ['email', 'username']
        }
      ]
    })

    if (!article) {
      throw new NotFound('没有找到这篇文章')
    }

    if (article.status != 2) {
      throw new AuthFailed('文章不是禁用状态')
    }

    const flag = data.get('info')

    if(!flag){
      await article.update({
        status: 0
      })
    }

    const r = await Mailer.send({
      to: article.user.email,
      type: 'unlock_article',
      title: `您的文章《${article.title}》解禁请求${flag ? '被驳回' : '成功'}`,
      article_title: article.title,
      info: flag
    })
    
    return r;
  }

  static async updateStatus(data, ctx){
    const article = await Article.findOne({
      where: {
        id: data.get('id')
      },
    })

    if (!article) {
      throw new NotFound('没有找到这篇文章')
    }

    if(article.user_id != ctx.auth.id){
      throw new AuthFailed('你没有权限修改这篇文章的状态')
    }

    if(article.status == 2){
      throw new AuthFailed('这篇文章处于禁用状态，无法修改！')
    }

    await article.update({
      status: data.get('status')
    })
  }
}

module.exports = ArticleController
